/*
 * @Author: ipk518 18163976442@163.com
 * @Date: 2023-08-19 16:03:22
 * @LastEditors: ipk518 121206530@qq.com
 * @LastEditTime: 2024-09-27 10:30:56
 * @FilePath: /WingsUpdater-main/src/DataTransmission/IDataTransmission.cpp
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */

#include "IDataTransmission.h"
#include "DataTransmissionTcp.h"
#include "DataTransmissionUdp.h"
#include "myLog.h"
#include "Crc.h"
#include "string.h"

using namespace std;

const size_t IDataTransmission::m_queMaxSize = 128;

shared_ptr<IDataTransmission> IDataTransmission::create(const int type) 
{
    shared_ptr<IDataTransmission> ins = nullptr;
    switch (type)
    {
        case DATA_TRANSMISSION_TCP:
            ins = shared_ptr<IDataTransmission>(new DataTransmissionTcp);
        break;
        case DATA_TRANSMISSION_UDP:
            ins = shared_ptr<IDataTransmission>(new DataTransmissionUdp);
        break;
        default:
        break;
    }

    return ins;
}

Result IDataTransmission::init(const initializer_list<void *> attr) 
{
    return Result::create(ErrorKind::InitFailed);
}

bool IDataTransmission::wait(const int64_t timeout) 
{
    auto ret = false;
    unique_lock lock(m_queMtx);
    if (0 == timeout) 
    {
        ret = false == m_recvQue.empty();
    }
    else if (timeout < 0) 
    {
        m_queCond.wait(lock, [&]{
            return false == this->m_recvQue.empty();
        });
        ret = true;
    }
    else 
    {
        ret = m_queCond.wait_for(lock, chrono::milliseconds(timeout), [&]{
            return false == this->m_recvQue.empty();
        });
    }

    return ret;
}

size_t IDataTransmission::available() 
{
    lock_guard<mutex> guard(m_queMtx);
    return m_recvQue.size();
}

Result IDataTransmission::transmit(const std::vector<uint8_t> &src) 
{
    return this->transmit(src.data(), src.size());
}

void IDataTransmission::asyncRecv(const void *src, const size_t size) 
{
    (void)size;
    unique_lock<mutex> guard(m_queMtx);
    if(m_recvQue.size() >= m_queMaxSize) 
    {
        this->release(m_recvQue.front());
        m_recvQue.pop();
    }
    m_recvQue.push(const_cast<void *>(src));
    m_queCond.notify_one();
}

void *IDataTransmission::take() 
{
    unique_lock<mutex> guard(m_queMtx);
    if(false == m_recvQue.empty()) 
    {
        auto data = m_recvQue.front();
        m_recvQue.pop();
        return data;
    }

    return nullptr;
}

static WingsUpdateReplyTcpUdp res; //用于应答上位机
static WingsUpdateHeaderTcpUdp item;//用于接收数据包
static system_para_t packPara;
#define WING_HEAD_SIZE  20
void *IDataTransmission::dataResolver(const std::vector<uint8_t> &buf,WingsInternalWrapper &src)
{
    uint32_t version = WINGS_VERSION;
    uint32_t mCrc32 = 0;
    memcpy((uint8_t *)&item,buf.data(),WING_HEAD_SIZE);
    // memcpy(item.dataEntity,&buf[20],(buf.size() - 20));
   
    if (item.header == WINGS_HEADER && item.tail == WINGS_TAIL) 
    {
        memset(res.dataEntity,0,sizeof(res.dataEntity));
        res.header = DSP_HEADER;
        res.type = item.type;
        res.tail = WINGS_TAIL;
        if(item.dataSize > 0) {
            mCrc32 = Crc::crc32((buf.data() + WING_HEAD_SIZE),item.dataSize);
            if (mCrc32 != item.crc32) {
                qlog_e("dataEntity crc32 error:remote:%#x,calc:%#x",item.crc32,mCrc32);
                qlog_hexdump("Header",16,(uint8_t *)buf.data(),WING_HEAD_SIZE);
                qlog_i("buf size:%d.",buf.size());
                return nullptr;
            }
        } 
        switch (item.cmdType)
        {
        case WINGS_QUERY:
            /* code */
            qlog_i("cmd:Query version.");
            res.cmdType = WINGS_QUERY;
            res.dataSize = 4;
            res.dataEntity[0] = (uint8_t)version;
            res.dataEntity[1] = (uint8_t)(version>>8);
            res.dataEntity[2] = (uint8_t)(version>>16);
            res.dataEntity[3] = (uint8_t)(version>>24);
            res.crc32 = Crc::crc32(res.dataEntity,res.dataSize);
            break;
        case WINGS_START:
            packPara.uBoot = false;
            if (!packPara.uBoot) {
                qlog_i("cmd:Handshake protocol.");
                //发送请求协议包
                packPara.uBoot = true;
                uint8_t mHeaderSize = 8;
                uint8_t uTemp[8];//数据实体内的 4字节 更新包总长度+ 4字节 更新包CRC32校验
                std::vector<uint8_t> packName;
                for(int i=0;i<mHeaderSize;i++) {
                    uTemp[i] = buf[i+WING_HEAD_SIZE];
                }
                packPara.uSize = *(uint32_t *)uTemp;//获取数据包总长度
                packPara.uCrc32 = *(uint32_t *)&uTemp[4];//获取更新包CRC32校验值

                packPara.uBuffer.clear();
                packPara.uBuffer.resize(packPara.uSize);//设置压缩包大小
                // packName.insert(packName.begin(),&item.dataEntity[8],(item.dataEntity + item.dataSize));
                
                std::string str((buf.begin() + WING_HEAD_SIZE + 8),buf.end());
                packPara.fileName = str;//获取更新包名字

                res.cmdType = WINGS_START;
                res.dataSize = 0;
                res.crc32 = 0;
                qlog_i("fileName:%s",str.c_str());
            }
            break;
        case WINGS_UPDATE:
            if (packPara.uBoot) {
                // qlog_i("cmd:Data protocol.");s
                uint8_t uTemp[4];//获取当前数据包的偏移量
                for(int i=0;i<4;i++) {
                    uTemp[i] = buf[i+WING_HEAD_SIZE];
                }
                uint32_t uOffset = *(uint32_t *)uTemp;
                
                for(int i = 0; i < (item.dataSize - 4); i++) 
                {
                    packPara.uBuffer[uOffset + i] = buf[WING_HEAD_SIZE + 4 + i];
                }

                if (uOffset == 0) {
                    packPara.uBoot = false;//数据包接收完成
                    uint32_t mCrc32 = Crc::crc32(packPara.uBuffer.data(),packPara.uBuffer.size());
                    if(mCrc32 == packPara.uCrc32) {
                        qlog_i("package crc32 check succeed. %#x",mCrc32);
                        qlog_i("start update.");
                        
                        src.name = std::move(packPara.fileName);
                        src.byteArray = std::move(packPara.uBuffer);
                    }
                    return nullptr;
                } else {
                    uint32_t dataLen = item.dataSize - 4;//收到数据包实体长度 -4 (去掉偏移量)
                    if(uOffset + dataLen >= packPara.uSize) //计算上报请求的数据包数据偏移地址
                        packPara.uNext = 0;
                    else
                        packPara.uNext = uOffset + dataLen;
                }
                

                res.cmdType = WINGS_UPDATE;
                res.dataSize = 4;
                res.dataEntity[0] = (uint8_t)packPara.uNext;
                res.dataEntity[1] = (uint8_t)(packPara.uNext>>8);
                res.dataEntity[2] = (uint8_t)(packPara.uNext>>16);
                res.dataEntity[3] = (uint8_t)(packPara.uNext>>24);
                res.crc32 = Crc::crc32(res.dataEntity,res.dataSize);
            }
            break;
        default:
            return nullptr;
            break;
        }
        return (void *)&res;
    }
    return nullptr;
    
}